/*
  TypeScript不是一门新的语言，就是一个强类型版本的js

  ts可以做运行时报错

  语法更加严格, 不容易出错

  更适合多人开发的大型项目


  1. 全局安装ts
    cnpm i typescript -g

  2. 编译ts文件
    tsc ./src/index.ts --outFile ./dist/index.js

  3. 初始化ts的配置文件
    tsc --init

  4. 开启实时监听
    tsc --watch
*/

// 定义字符串类型变量
// 定义好了类型之后就不能改成其他类型的变量了
// ts有自动类型推断功能
let str: string = "hello ts";

let str2: string;
str2 = "hi";

// 定义数字类型
let num: number = 10;
// 就只能使用数字能用的一些方法
num / 2;

// 定义布尔值
let done: boolean = true;
done = false;

// 定义undefined
// undefined类型只有一个值就是undefined，所以不能再做任何的修改了
let udf: undefined = undefined;

// 定义null
// null类型只有一个值就是null，所以不能再做任何的修改了
let nl: null = null;

// 联合类型(既可能是这个类型，也可能是那个类型)
let a: number | string | boolean = 3;
a = "3";
a = 100;
a = true;

// const keys: string | null = localStorage.getItem("keys");
// const arr = keys && JSON.parse(keys);

// 定义any类型
// 任意类型
// 尽可能少用
let b: any = { name: "zhangsan" };
b = false;
b = 3;

// 定义数组类型
// 数组要精确到里面每一项的数据类型
let arr1: number[] = [1, 2, 3, 4, 5];
let arr2: Array<number> = [1, 2, 3, 4, 5];
let arr3: (number | string)[] = [1, 2, "hello"];
// arr3.push(true);
let arr4: Array<number | string> = [1, 2, "hello"];

// 定义元组类型(数组类型的扩展)
// 规定了数组的长度以及具体的每一项的数据类型
let arr5: [number, boolean] = [1, true];

// 定义对象类型
// 定义对象的时候，需要用到interface
interface Obj1Type {
  name: string | boolean;
  age: number;
  // 问号表示可选属性
  sex?: number;
  // 索引签名
  // 除了上面规定好的数据类型以外，剩下的类型不在意了，就可以使用索引签名
  [propName: string]: any;
}
let obj1: Obj1Type = {
  name: "tom",
  age: 30,
};
obj1.age = 90;
obj1.sex = 1;
obj1.aa = true;
obj1.bb = [1, 2, 3];

interface Obj2Type {
  x: number;
  y: number;
  z: string[];
}
let obj2: Obj2Type = {
  x: 10,
  y: 20,
  z: ["11", "22", "33"],
};

interface ItemType {
  id: number;
  name: string;
}
let obj3: ItemType[] = [
  {
    id: 1,
    name: "zhangsan",
  },
  {
    id: 2,
    name: "lisi",
  },
];

interface Item2Type {
  id: number;
  name: string;
  children?: Item2Type[];
}
let obj4: Item2Type[] = [
  {
    id: 1,
    name: "zhangsan",
    children: [
      {
        id: 11,
        name: "zhangsi",
      },
      {
        id: 12,
        name: "zhangwu",
      },
    ],
  },
  {
    id: 2,
    name: "liliu",
  },
];

interface AttrType {
  height: number;
  weight: number;
}
interface Obj5Type {
  name: string;
  likes: string[];
  attrs: AttrType;
}
let obj5 = {
  name: "zhangsan",
  likes: ["唱", "跳"],
  attrs: {
    height: 180,
    weight: 200,
  },
};

// 定义函数类型
// 函数加的是它返回值的类型
function fn(): number {
  return 10;
}
// 函数参数无法推断，一定要加数据类型
function fn2(x: number, y: string): string {
  return x + y;
}
fn2(3, "4");

// 问号表示可选参数
function fn3(x: number, y?: number): number {
  if (y) {
    return x + y;
  } else {
    return x;
  }
}
fn3(3, 4);
fn3(3);

const fn4: (a: number, b: number) => number = (
  a: number,
  b: number
): number => {
  return a + b;
};
fn4(5, 6);

// 当一个函数没有返回值的，返回值类型要写void
const fn5 = (): void => {
  console.log(123);
};

// 泛型类型(函数的补充)
function fn6<T>(x: T, y: T) {
  return 100;
}
fn6<number>(3, 4);
fn6<string>("3", "4");

// const [count, setCount] = useState<number>(10);
